package com.ocean.courtyard.command;

import com.ocean.courtyard.constants.ConstantsAttribute;
import com.ocean.courtyard.core.datasource.SqlSessionImpl;
import com.ocean.courtyard.core.worldguard.WorldGuardSetting;
import com.ocean.courtyard.entity.CourtyardHome;
import com.ocean.courtyard.exception.MaxHomesLimitException;
import com.ocean.courtyard.message.Message;
import com.ocean.courtyard.util.FileUtils;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.*;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.logging.Level;
import java.util.stream.Stream;

/**
 * 世界导入
 *
 * @author zhang
 * @since 2024年11月24日
 */
public class ImportCommand implements CommandExecutor {

    private final JavaPlugin plugin;

    private final MultiverseCore core;

    private final SqlSessionImpl sqlSession;

    private final Message message;

    private final Player player;

    private final WorldGuardSetting worldGuardSetting;

    public ImportCommand(JavaPlugin plugin, SqlSessionImpl sqlSession, Message message, Player player, WorldGuardSetting worldGuardSetting) {
        this.plugin = plugin;
        this.core = JavaPlugin.getPlugin(MultiverseCore.class);
        this.sqlSession = sqlSession;
        this.message = message;
        this.player = player;
        this.worldGuardSetting = worldGuardSetting;
    }

    @Override
    public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
        try {
            // 家园数量校验
            verifyHomes(player);

            MVWorldManager manager = core.getMVWorldManager();
            String templateWorldName = args[1];
            String worldAlias = getAlias(player);
            String templateFile = FileUtils.getTemplateFile(templateWorldName, plugin);
            String newWorldName = FileUtils.getWorldPath(player, plugin).replace("\\", "/");

            createWorldAsync(player, manager, templateFile, newWorldName, worldAlias);
            return true;
        } catch (MaxHomesLimitException e) {
            return false;
        } catch (Exception e) {
            plugin.getLogger().log(Level.SEVERE, "An error occurred while creating the world.", e);
            return false;
        }
    }

    private void createWorldAsync(Player player, MVWorldManager manager, String templateFile, String newWorldName, String worldAlias) {
        new BukkitRunnable() {
            @Override
            public void run() {
                if (copyTemplateWorld(templateFile, newWorldName)) {
                    if (!manager.addWorld(newWorldName, World.Environment.NORMAL, null, WorldType.NORMAL, true, null, true)) {
                        plugin.getLogger().warning("Failed to import world: " + newWorldName);
                    } else {
                        completeWorldCreation(player, manager, newWorldName, worldAlias);
                    }
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    private void completeWorldCreation(Player player, MVWorldManager manager, String newWorldName, String worldAlias) {
        String serverHome = plugin.getConfig().getString(ConstantsAttribute.SERVER_NAME);
        MultiverseWorld world = manager.getMVWorld(newWorldName);
        if (world != null) {
            World cbWorld = world.getCBWorld();
            initWorld(world, worldAlias);
            setFlag(cbWorld, player.getName());
            Location location = cbWorld.getSpawnLocation();
            //新增数据
            CourtyardHome courtyardHome = new CourtyardHome(player.getName(), serverHome, location.getX(), location.getY(), location.getZ(), newWorldName);
            sqlSession.addHome(courtyardHome);
            message.sendWorldImportSuccessMessage(player);
        }
    }

    private void verifyHomes(Player player) {
        int maxHomes = plugin.getConfig().getInt(ConstantsAttribute.MAX_HOMES);
        Integer homeNumber = sqlSession.getHomeNumber(player.getName());
        if (homeNumber >= maxHomes) {
            message.sendMaxHomesLimitMessage(player);
            throw new MaxHomesLimitException("Maximum homes: " + maxHomes);
        }
    }

    private void initWorld(MultiverseWorld world, String alias) {
        world.setAlias(alias);
        world.setDifficulty(Difficulty.HARD);
        world.setGameMode(GameMode.SURVIVAL);
        world.setKeepSpawnInMemory(false);
    }

    private void setFlag(World world, String playerName) {
        worldGuardSetting.setHomeDefaultFlag(world, playerName);
    }

    private boolean copyTemplateWorld(String templateWorldName, String newWorldName) {
        File templateWorldFolder = new File(templateWorldName);
        File newWorldFolder = new File(Bukkit.getWorldContainer(), newWorldName);

        if (!templateWorldFolder.exists() || !templateWorldFolder.isDirectory()) {
            plugin.getLogger().severe("Template world folder does not exist or is not a directory.");
            return false;
        }

        try (Stream<Path> stream = Files.walk(templateWorldFolder.toPath())) {
            stream.forEach(source -> {
                try {
                    Files.copy(source, newWorldFolder.toPath().resolve(templateWorldFolder.toPath().relativize(source)), StandardCopyOption.REPLACE_EXISTING);
                } catch (IOException e) {
                    plugin.getLogger().severe("Failed to copy template world: " + e.fillInStackTrace());
                }
            });
            return true;
        } catch (IOException e) {
            plugin.getLogger().severe("Failed to walk through template world folder: " + e.fillInStackTrace());
            return false;
        }
    }

    public String getAlias(Player player) {
        String worldAlias = plugin.getConfig().getString(ConstantsAttribute.ALIAS);
        if (worldAlias != null) {
            return PlaceholderAPI.setPlaceholders(player, worldAlias);
        }
        return null;
    }
}
